package com.hippomeetsskunk.savanna.run;

import java.io.IOException;

import org.apache.log4j.Logger;
import org.drools.KnowledgeBase;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.command.CommandFactory;
import org.drools.compiler.DroolsParserException;
import org.drools.io.Resource;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.CommandExecutor;
import org.drools.runtime.StatefulKnowledgeSession;

import com.hippomeetsskunk.savanna.types.world.Region;
import com.hippomeetsskunk.savanna.types.world.World;

public class RuleRunner {

	public static final String START_DAY = "1";
	
	private static final Logger logger = Logger.getLogger(RuleRunner.class);
	private static final Logger gsLogger = Logger.getLogger("com.hippomeetsskunk.savanna.rules.GoalSetting");
	private static final Logger geLogger = Logger.getLogger("com.hippomeetsskunk.savanna.rules.GoalExecution");
	private static final Logger mkLogger = Logger.getLogger("com.hippomeetsskunk.savanna.rules.Market");
	
	private final String[] ruleflows = new String[] {
			"flow/flow.rf"
	};
	private final String[] rules = new String[] {
			"rules/test.drl",
			"rules/goalsetting.drl",
			"rules/goalexecution.drl",
			"rules/market.drl"
	};
	
	public void simulate(World world, int days){
		KnowledgeBase knowledgeBase = createKnowledgeBase();
		CommandExecutor session = createSession(knowledgeBase, world);
		
		// needed, or is event enough?
		for(int i=0; i<days; ++i){
			runProcess(START_DAY, session);
		}
		
		// TODO if switching to stateful session, dispose it here
	}
	
	public void runRules(String process, World world) throws DroolsParserException, IOException{
		KnowledgeBase knowledgeBase = createKnowledgeBase(ruleflows, rules);
		CommandExecutor session = createSession(knowledgeBase, world);
		runProcess(process, session);
	}
	
	public KnowledgeBase createKnowledgeBase(){
		return createKnowledgeBase(ruleflows, rules);
	}
	
	public KnowledgeBase createKnowledgeBase(String[] ruleflows, String[] rules){
		KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
		for (String ruleflow : ruleflows) {
			logger.trace("Loading flow: " + ruleflow);
			Resource resource = ResourceFactory.newClassPathResource(ruleflow);
			if (resource != null){
				// or switch to BPMN2 ?
				knowledgeBuilder.add(resource, ResourceType.DRF);
			}
		}
		for (String ruleFile : rules) {
			logger.trace("Loading rules: " + ruleFile);
			Resource resource = ResourceFactory.newClassPathResource(ruleFile);
			knowledgeBuilder.add(resource, ResourceType.DRL);
		}
		
		KnowledgeBase knowledgeBase = knowledgeBuilder.newKnowledgeBase();
		return knowledgeBase;
	}
	
	@SuppressWarnings("unchecked")
	public CommandExecutor createSession(KnowledgeBase knowledgeBase, World world){

		StatefulKnowledgeSession session = knowledgeBase.newStatefulKnowledgeSession();
		// StatelessKnowledgeSession session = knowledgeBase.newStatelessKnowledgeSession();

		if(logger.isTraceEnabled()){
			KnowledgeRuntimeLoggerFactory.newConsoleLogger(session);
		}
		
		session.execute(CommandFactory.newSetGlobal("world", world));
		session.execute(CommandFactory.newSetGlobal("logger", logger));
		session.execute(CommandFactory.newSetGlobal("gsLogger", gsLogger));
		session.execute(CommandFactory.newSetGlobal("geLogger", geLogger));
		session.execute(CommandFactory.newSetGlobal("mkLogger", mkLogger));
		
		for(Region r : world.getRegions()){
			logger.trace("inserting persons");
			session.execute(CommandFactory.newInsertElements(r.getPersons()));
		}
		
		return session;
	}
	
	
	@SuppressWarnings("unchecked")
	public void runProcess(String process, CommandExecutor session){
		session.execute(CommandFactory.newStartProcess(process));
		session.execute(CommandFactory.newFireAllRules());
	}
	
}
